package com.bjpowernode.core;

import com.bjpowernode.constant.Constant;
import com.bjpowernode.util.FileUtils;
import com.bjpowernode.util.HttpUtils;
import com.bjpowernode.util.LogUtils;
import java.io.*;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.concurrent.*;
import static com.bjpowernode.constant.Constant.THREAD_NUM;

/**
 * @author admin
 */
public class Downloader {

    public ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
    /**
     * 线程池对象
     * @param url
     */
    public ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(THREAD_NUM, THREAD_NUM,0,java.util.concurrent.TimeUnit.SECONDS,new ArrayBlockingQueue<>(THREAD_NUM));

    private CountDownLatch countDownLatch = new CountDownLatch(THREAD_NUM);

    public void download(String url) {
        //获取文件名
        String httpFileName = HttpUtils.getHttpFileName(url);
        //拼接文件路径
        httpFileName = Constant.PATH + httpFileName;
        //获取本地文件的大小
        long localFileContentLength = FileUtils.getFileContentLength(httpFileName);
        //获取链接对象
        HttpURLConnection httpURLConnection = null;
        DownloadInfoThread downloadInfoThread = null;
        try{
            httpURLConnection = HttpUtils.getHttpURLConnection(url);
            //获取网络文件的大小
            int contentLength = httpURLConnection.getContentLength();
            //判断本地文件是否存在
            if(localFileContentLength == contentLength){
                LogUtils.info("{}文件已经下载过了",httpFileName);
                return;
            }
            //创建获取下载信息的任务对象
            downloadInfoThread = new DownloadInfoThread(contentLength);
            //将任务提交给线程池执行,每秒执行一次
            scheduledExecutorService.scheduleAtFixedRate(downloadInfoThread,1,1,java.util.concurrent.TimeUnit.SECONDS);
            //切分任务
            ArrayList<Future> futureList = new ArrayList<>();
            split(url,futureList);

//            //循环获取任务执行结果
//            futureList.forEach(future -> {
//                try {
//                    future.get();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                } catch (ExecutionException e){
//                    e.printStackTrace();
//                }
//            });

            countDownLatch.await();

            //合并文件
            if(merge(httpFileName)){
                //清除临时文件
                clearTemp(httpFileName);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.println("\r");
            System.out.println("下载完成");
            //关闭连接对象
            if(httpURLConnection != null){
                httpURLConnection.disconnect();
            }
            //关闭线程
            scheduledExecutorService.shutdownNow();
            //关闭线程池
            poolExecutor.shutdown();
        }
    }

    /**
     * 下载信息的任务
     */
    public void split(String url, ArrayList<Future> futureList){
        try{
            //获取下载文件大小
            long contentLength = HttpUtils.getHttpFileContentLength(url);
            //计算切分后的文件大小
            long size = contentLength / THREAD_NUM;
            //计算分块大小
            for(int i = 0; i < THREAD_NUM; i++){
                //计算下载开始位置
                long startPos = i * size;
                //计算下载结束位置
                long endPos;
                if(i == THREAD_NUM - 1) {
                    endPos = 0;
                }else{
                    endPos = startPos + size;
                }

                //如果不是第一块，起始位置需要加1
                if(startPos != 0){
                    startPos++;
                }
                //创建任务对象
                DownloaderTask downloaderTask = new DownloaderTask(url,startPos,endPos,i,countDownLatch);
                //将任务提交给线程池
                Future<Boolean> future = poolExecutor.submit(downloaderTask);
                //将任务对象添加到集合中
                futureList.add(future);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    /**
     * 合并文件
     * @param fileName
     * @return
     */
    public boolean merge(String fileName){
        System.out.println("\r");
        LogUtils.info("开始合并文件",fileName);
        byte[] buffer = new byte[Constant.BYTE_SIZE];
        int len = -1;
        try(RandomAccessFile accessFile = new RandomAccessFile(fileName,"rw")){
            for(int i = 0; i < THREAD_NUM; i++){
                try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName + ".temp" + i))){
                    while((len = bis.read(buffer)) != -1){
                        accessFile.write(buffer,0,len);
                    }
                }
            }
            System.out.println("\r");
            LogUtils.info("文件合并完成",fileName);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 清除临时文件
     * @param fileName
     * @return
     */
    public boolean clearTemp(String fileName){
        for(int i = 0; i < Constant.THREAD_NUM; i++){
            File file = new File(fileName + ".temp" + i);
            file.delete();
        }
        return true;
    }

}
